//==============================================================================
// PowerPlayerController
//
// handles cover system.  handles input.  handles sprinting.
//
// Contact : contact@whitemod.com
// Website : www.whitemod.com
// License : Content is available under Creative Commons Attribution-ShareAlike
//			 3.0 License.
//==============================================================================

class PowerPlayerController extends UTPlayerController
	dependson(PowerCoverManager);

`define Trace(obj) `obj.Run( self );

// have we pressed the cover button?
var	bool	TryingCover;
// are we actually taking cover?
var	bool	TakingCover;

var PowerCoverManager CoverManager;
var bool bCoverAvailable;
var CoverLink CurrentCoverLink;
var int CurrentCoverSlot;

simulated event PostBeginPlay()
{
	//local int i;
	CoverManager = spawn(class'PowerCoverManager');
	if (CoverManager.CoverList.Length > 0)
		bCoverAvailable = true;

	`log("[PlayerController] CoverAvailable="$bCoverAvailable);

	/*
	for (i=0; i < CoverManager.CoverList.Length; i++)
	{
		ClientMessage(CoverManager.GetCoverInfo());
		`log(CoverManager.GetCoverInfo());
	}
	*/
	Super.PostBeginPlay();
}

exec function ToggleCoverState()
{
	TryingCover = !TryingCover;
	//`log("TryingCover="$TryingCover);
}

// does stuff with the input
simulated function CheckInput( float DeltaTime )
{
	if ( TryingCover && bCoverAvailable )
	{
		//`log("Cover available, trying to take cover");
		if ( IsInState( 'Peeking' ) || IsInState( 'Covering' ) )
		{
			//`log("Exiting Cover");
	   		EndCover();
		}
	   	else
  	 	{
			//`log("Trying Cover");
			TryCover();
		}
	}
}

simulated function bool CheckCoverAutoCrouch()
{
	return CoverManager.CoverCrouchRequired(CurrentCoverLink, CurrentCoverSlot);
}

simulated function TryCover()
{
	local CoverLink PotentialCover;
	local int PotentialCoverSlot;

	PotentialCover = CoverManager.GetClosestCoverLink(Pawn.Location);

	if (PotentialCover != none)
	{
		CurrentCoverLink = PotentialCover;
		PotentialCoverSlot = CoverManager.GetClosestCoverSlot(Pawn, PotentialCover);

		if (PotentialCoverSlot != -1)
		{
			CurrentCoverSlot = PotentialCoverSlot;
			BeginCover();
		}
		else // No cover slot available nearby
		{
			EndCover();
		}
	}
}

simulated function BeginCover()
{
	TryingCover = false;
	TakingCover = true;

	GotoState('Covering');
}

simulated function EndCover()
{
	TryingCover = false;
	TakingCover = false;
	if ( IsInState( 'Covering' ) )
		GotoState( 'PlayerWalking' );
	// might need to add code here for stacking. Probably won't though, the player shouldn't have to exit cover
}

simulated event GetPlayerViewPoint( out vector POVLocation, out Rotator POVRotation )
{
	local float DeltaTime;

	SetBehindView( true );

	DeltaTime = WorldInfo.TimeSeconds - LastCameraTimeStamp;

	if ( PlayerCamera == None )
	{
		SpawnPlayerCamera();
		SetViewTarget( PlayerCamera );
	}

	if ( PlayerCamera != None)
	{
		if ( Pawn != None )
			PlayerCamera.SetViewTarget( Pawn );

		PlayerCamera.UpdateCamera( DeltaTime );
		PlayerCamera.GetCameraViewPoint( POVLocation, POVRotation );
	}
	LastCameraTimeStamp = WorldInfo.TimeSeconds;
}

/******************** PLAYER UPDATE *******************/
// just gather input for now
event PlayerTick( float DeltaTime )
{
	CheckInput( DeltaTime );

	super.PlayerTick( DeltaTime );

	PowerCamera(PlayerCamera).SetInputs( PlayerInput.aForward, PlayerInput.aStrafe, PlayerInput.aUp );
}

state PlayerWalking
{
	function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
	{
		Super.ProcessMove( DeltaTime, NewAccel, DoubleClickMove, DeltaRot );
	}
}

/******************** COVER STATES *******************/
state Covering extends PlayerWalking
{
	function BeginState( name PreviousStateName )
	{
		local rotator CoverRotation;
		local int CoverDirection;
		local string dump;

		//`log("Covering");
		dump = CoverManager.GetCoverInfo();
		`log(dump);
		CurrentCoverLink.Claim(Pawn, CurrentCoverSlot);

		SetBehindView( true );

		if ( Pawn != None )
			Pawn.GroundSpeed *= 0.8;

		CoverRotation = CurrentCoverLink.GetSlotRotation(CurrentCoverSlot);
		CoverRotation.Pitch = 0;
		Pawn.SetRotation( -1*CoverRotation );

		if (CheckCoverAutoCrouch())
		{
			bDuck = 1;
		}

		PlayerCamera.GotoState( 'Covering' );

		Super.BeginState( PreviousStateName );
	}

	function EndState( name NextStateName )
	{
		bDuck = 0;

		if ( Pawn != None )
			Pawn.GroundSpeed = Pawn.Default.GroundSpeed;

		Super.EndState( NextStateName );
		PlayerCamera.GotoState( 'Lazy' );

  		//`log( "Ended Cover" );
	}

	function PlayerMove( float DeltaTime )
	{
		local Rotator OldRotation;
		local vector			X,Y,Z, NewAccel;
		local eDoubleClickDir	DoubleClickMove;
		local int               NextCoverSlot;

		if( Pawn == None )
		{
			GotoState('Dead');
			return;
		}

		if ( CoverManager.GetCoverDirection(CurrentCoverLink, CurrentCoverSlot) != 0 && (VSize(CurrentCoverLink.GetSlotLocation(CurrentCoverSlot) - Pawn.Location) <= 25) )
		{
			if ( CoverManager.GetCoverDirection(CurrentCoverLink, CurrentCoverSlot) == -1 && (PlayerInput.aStrafe < 0) )
			{
				return;
			}
			else if ( CoverManager.GetCoverDirection(CurrentCoverLink, CurrentCoverSlot) == 1 && (PlayerInput.aStrafe > 0) )
			{
				return;
			}
		}

		NextCoverSlot = CoverManager.GetClosestCoverSlot(Pawn, CurrentCoverLink);
		if ( NextCoverSlot != CurrentCoverSlot )
		{
			CurrentCoverLink.UnClaim(Pawn, CurrentCoverSlot, false);
			CurrentCoverSlot = NextCoverSlot;
			GotoState('Covering');
		}

		GroundPitch = 0;

		X = CoverManager.GetSurfaceTangent(CurrentCoverLink, CurrentCoverSlot);
		NewAccel = -PlayerInput.aStrafe*X;

		NewAccel.Z	= 0;
		NewAccel = Pawn.AccelRate * Normal(NewAccel);

		// now we make sure we move a little bit towards the wall we are pressing on...
		// this is used for cylinders and such.
		NewAccel += Max( 0.25, ( VSize( NewAccel ) / Pawn.AccelRate ) ) * ( Pawn.AccelRate * ( VSize( -1.0f*Vector(CurrentCoverLink.GetSlotRotation(CurrentCoverSlot)) - Pawn.Mesh.GetBoneLocation( 'b_Hips' ) ) / 10 ) * -Y );
		DoubleClickMove = PlayerInput.CheckForDoubleClickMove( DeltaTime/WorldInfo.TimeDilation );

		// Update rotation.
		UpdateRotation( DeltaTime );
		bDoubleJump = false;

		if( bPressedJump )
		{
			bPressedJump = false;
		}

		if( Role < ROLE_Authority ) // then save this move and replicate it
			ReplicateMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
		else
			ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
	}

	simulated event GetPlayerViewPoint( out vector POVLocation, out Rotator POVRotation )
	{
		local float DeltaTime;

		DeltaTime = WorldInfo.TimeSeconds - LastCameraTimeStamp;

		if ( PlayerCamera == None )
		{
			SpawnPlayerCamera();
			Global.SetViewTarget( PlayerCamera );
		}

		if ( Pawn != None )
			SetViewTarget( Pawn );

		PlayerCamera.UpdateCamera( DeltaTime );
  		PlayerCamera.GetCameraViewPoint( POVLocation, POVRotation );

		LastCameraTimeStamp = WorldInfo.TimeSeconds;
	}
}

defaultproperties
{
	bCoverAvailable=false

	CameraClass = Class'PowerCamera'
}
